package com.xneure.utils.bean;

import java.beans.PropertyDescriptor;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.lang3.time.FastDateFormat;

/**
 * <p>
 * 表达式解析器
 * </p>
 * <p>
 * Copyright: 版权所有<br>
 *	简单的小工具
 * @version 2018年8月16日
 */
public class BeanExpression{
	private FastDateFormat instance = FastDateFormat.getInstance("yyyy年MM月dd日");

	protected Object findFieldValue(Object obj,String fd){
		if(obj instanceof Collection){
			@SuppressWarnings({"unchecked","rawtypes"})
			Iterator<Object> it = ((Collection)obj).iterator();
			while(it.hasNext()){
				Object tmp = findFieldValue(it.next(),fd);
				if(null != tmp){
					return tmp;
				}
			}
		}else if(obj.getClass().isArray()){
			return findFieldValue(Arrays.asList((Object[])obj),fd);
		}else if(obj instanceof Map){
			return obj;
		}else{
			try{
				PropertyDescriptor pd = new PropertyDescriptor(fd,obj.getClass());
				return pd.getReadMethod().invoke(pd);
			}catch(Exception e){
			}
		}
		return null;
	}

	/**
	 * 通过表达式获取对象属性值，支持级联操作 ${obj.user.name} 获取值 ${obj.user[1].name} 支持数组 list map
	 *  !${} 非空结果
	 * @param obj
	 * @param field ${obj.name}
	 * @return Object
	 */
	public String getValue(Object obj,String field){
		if(null == field || null == obj || field.trim().length() < 1 || field.contains("${") == false){
			return field;
		}
		if(field.contains(" & ")){
			String[] str = field.split(" & ");
			StringBuilder sb = new StringBuilder();
			for(String ts:str){
				Object value = getValue(obj,ts);
				if(null != value && value.toString().length() > 0){
					sb.append(" / ").append(value);
				}
			}
			return sb.length() > 3 ? sb.substring(3) : "";
		}
		int notNull = 0;
		if(field.contains("!${")){
			notNull = 1;
		}
		String[] _field = field.split("[!]*\\$\\{|\\}");
		StringBuilder strBuilder = new StringBuilder();
		for(int si = 0;si < _field.length;si++){
			if(isIgnore(_field[si])){
				strBuilder.append(_field[si]);
				continue;
			}
			field = _field[si];
			Object tmpObj = obj;
			if(field.contains(".")){
				String[] str = field.split("\\.");
				int index = -1;
				int sl = str.length;
				for(int i = 0;i < sl;i++){
					String s = str[i];
					index = s.indexOf("[");
					if(index > 1){
						String key = s.substring(index + 1,s.length() - 1);
						s = s.substring(0,index);
						tmpObj = findFieldValue(tmpObj,s);
						tmpObj = fetchValue(tmpObj,key);
						if(null == tmpObj){
							break;
						}
					}else{
						tmpObj = findFieldValue(tmpObj,s);
						if(tmpObj.getClass().isArray()){
							tmpObj = Arrays.asList(tmpObj);
						}else if(tmpObj instanceof Map){
							tmpObj = ((Map<?,?>)tmpObj).values();
						}
						if(tmpObj instanceof Collection){
							@SuppressWarnings({"unchecked","rawtypes"})
							Iterator<Object> it = ((Collection)tmpObj).iterator();
							StringBuilder sBuilder = new StringBuilder();
							Object tobj = null;
							while(it.hasNext()){
								tobj = it.next();
								for(int _i = i + 1;_i < sl;_i++){
									tobj = findFieldValue(tobj,str[_i]);
									if(null == tobj){
										tmpObj = null;
										break;
									}
								}
								if(null != tobj){
									if(tmpObj.getClass().equals(Date.class) || tmpObj.getClass().equals(Timestamp.class)){
										tmpObj = instance.format(tmpObj);
									}
									if(null != tobj && tobj.toString().length() > 0){
										sBuilder.append(" / ").append(tobj);
									}
								}
							}
							if(sBuilder.length() > 3){
								tmpObj = sBuilder.substring(3);
							}
							break;
						} 
					}
					if(null == tmpObj){
						break;
					}
				}
			}else{
				tmpObj = findFieldValue(tmpObj,field);
			}
			if(null != tmpObj){
				if(tmpObj.getClass().equals(Date.class) || tmpObj.getClass().equals(Timestamp.class)){
					tmpObj = instance.format(tmpObj);
				}
			}
			if(notNull > 0 && null == tmpObj && si == 1){
				notNull = 2;
			}
			strBuilder.append(null == tmpObj ? field : tmpObj);
		}
		return notNull > 1 ? "" : strBuilder.toString();
	}

	private boolean isIgnore(String str){
		if(null == str || str.trim().length() < 1 || str.trim().indexOf("!") > -1){
			return true;
		}
		return false;
	}

	public Object fetchValue(Object obj,String key){
		if(null == key){
			return obj;
		}
		if(obj instanceof Collection){
			@SuppressWarnings({"unchecked","rawtypes"})
			Iterator<Object> it = ((Collection)obj).iterator();
			int index = 0;
			int point = Integer.valueOf(key);
			obj = null;
			while(it.hasNext()){
				if(index++ == point || null == key){
					obj = it.next();
					break;
				}else{
					it.next();
					obj = null;
				}
			}
		}else if(obj instanceof Map){
			obj = ((Map<?,?>)obj).get(key);
		}else if(obj.getClass().isArray()){
			obj = null == key ? obj : ((Object[])obj)[Integer.valueOf(key)];
		}
		return obj;
	}
}
